package com.controller;

/**
 * Created by lirance on 16/4/15.
 */

import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ClusterAnalysis {

    public List<Cluster> startAnalysis(List<DataPoint> dataPoints, int ClusterNum) {
        List<Cluster> finalClusters = new ArrayList<Cluster>();
        List<Cluster> originalClusters = initialCluster(dataPoints);
        finalClusters = originalClusters;

        while (finalClusters.size() > ClusterNum) {
            double min = Double.MAX_VALUE;
            int mergeIndexA = 0;
            int mergeIndexB = 0;
            for (int i = 0; i < finalClusters.size(); i++) {
                for (int j = 0; j < finalClusters.size(); j++) {
                    if (i != j) {
                        Cluster clusterA = finalClusters.get(i);
                        Cluster clusterB = finalClusters.get(j);
                        DataPoint centerA = getCenterPoint(clusterA);
                        DataPoint centerB = getCenterPoint(clusterB);
                        double tmpDis = getDistance(centerA, centerB);
                        if (tmpDis < min) {
                            min = tmpDis;
                            mergeIndexA = i;
                            mergeIndexB = j;
                        }
                    }
                }
            }
            finalClusters = mergeCluster(finalClusters, mergeIndexA, mergeIndexB);
        }
        return finalClusters;
    }

    //初始化类簇
    private List<Cluster> initialCluster(List<DataPoint> dataPoints) {
        List<Cluster> originalClusters = new ArrayList<Cluster>();
        for (int i = 0; i < dataPoints.size(); i++) {
            DataPoint tempDataPoint = dataPoints.get(i);
            List<DataPoint> tempDataPoints = new ArrayList<DataPoint>();
            tempDataPoints.add(tempDataPoint);
            Cluster tempCluster = new Cluster();
            tempCluster.setClusterName("Cluster" + String.valueOf(i));
            tempCluster.setDataPoints(tempDataPoints);
            tempDataPoint.setCluster(tempCluster);
            originalClusters.add(tempCluster);
        }
        return originalClusters;
    }

    private double getDistance(DataPoint dpA, DataPoint dpB) {
        double distance = 0;
        double[] dimA = dpA.getDimensioin();
        double[] dimB = dpB.getDimensioin();
        if (dimA.length == dimB.length) {
            for (int i = 0; i < dimA.length; i++) {
                distance += Math.pow(dimA[i] - dimB[i], 2);
            }
            distance = Math.pow(distance, 0.5);
        }
        return distance;
    }

    private List<Cluster> mergeCluster(List<Cluster> clusters, int mergeIndexA, int mergeIndexB) {
        if (mergeIndexA != mergeIndexB) {
            //将cluster[merageIndexB]中的dataPoints加入到cluster[merageIndexA]
            Cluster clusterA = clusters.get(mergeIndexA);
            Cluster clusterB = clusters.get(mergeIndexB);
            List<DataPoint> dpA = clusterA.getDataPoints();
            List<DataPoint> dpB = clusterB.getDataPoints();
            for (DataPoint dp : dpB) {
                DataPoint tempDp = new DataPoint();
                tempDp.setDataPointName(dp.getDataPointName());
                tempDp.setDimensioin(dp.getDimensioin());
                tempDp.setCluster(clusterA);
                dpA.add(tempDp);
            }
            clusterA.setDataPoints(dpA);
            clusters.remove(mergeIndexB);
        }
        return clusters;
    }

    private DataPoint getCenterPoint(Cluster cluster) {
        DataPoint centerPoint = new DataPoint();
        List<DataPoint> datapoints = cluster.getDataPoints();
        int len = datapoints.get(0).getDimensioin().length;
        double[] centerValue = new double[len];
        for (int i = 0; i < datapoints.size(); i++) {
            DataPoint temp = datapoints.get(i);
            double[] tempDim = temp.getDimensioin();
            for (int j = 0; j < tempDim.length; j++) {
                centerValue[j] += tempDim[j];
            }
        }
        for (int i = 0; i < centerValue.length; i++) {
            centerValue[i] = centerValue[i] / datapoints.size();
        }
        centerPoint.setDimensioin(centerValue);
        return centerPoint;
    }

    //List<Cluster>
    //主函数
    public static void main(String[] args) {
        ArrayList<DataPoint> dpoints = new ArrayList<DataPoint>();

        double[] serValue = new double[102];

        String path = "./src/com/controller/Performance of service.txt";

        try {
            File file = new File(path);
            FileReader fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);
            String line = "";
            int serId = 1;
            while (br.ready()) {
                line = br.readLine();
                String[] data = line.split("\t");
                serValue[serId] = Double.parseDouble(data[1]);
                serId++;
            }
            br.close();
            fr.close();
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        for (int j = 1; j < serValue.length; j++) {
            DataPoint temppoint = new DataPoint();
            temppoint.setDataPointName("s" + String.valueOf(j));
            double[] value = {serValue[j]};
            temppoint.setDimensioin(value);
            dpoints.add(temppoint);
        }

        int clusterNum = 10; //类簇数
//

        ClusterAnalysis ca = new ClusterAnalysis();
        //   Set set = new HashSet<String>();
        List<String> list = new ArrayList<String>();
        List<Cluster> clu = new ArrayList<Cluster>();
        List<Cluster> clusters = ca.startAnalysis(dpoints, clusterNum);
        for (Cluster cl : clusters) {
            //      set.add("---" + cl.getClusterName() + "---");
            list.add("---" + cl.getClusterName() + "---");
            System.out.println("---" + cl.getClusterName() + "---");
            List<DataPoint> points = cl.getDataPoints();
            for (DataPoint dp : points) {
                //          set.add(dp.getDataPointName() + ":" + dp.getDimensioin()[0] + " ");
                list.add(dp.getDataPointName() + ":" + dp.getDimensioin()[0] + " ");
                System.out.print(dp.getDataPointName() + ":" + dp.getDimensioin()[0] + " ");
            }
            // list.add("");
            clu.add(cl);
            System.out.println("");
        }

        //   return clusters;
        File fileout = new File("./src/com/controller/clusterResult.txt");

        Iterator iterator = list.iterator();
        FileWriter fw = null;
        BufferedWriter writer = null;
        try {
            fw = new FileWriter(fileout);
            writer = new BufferedWriter(fw);
            while (iterator.hasNext()) {
                writer.write(iterator.next().toString());
                writer.newLine();//换行
            }
            writer.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                writer.close();
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public List<DataPoint> getdataPoints() {
        ArrayList<DataPoint> dpoints = new ArrayList<DataPoint>();

        double[] serValue = new double[102];

        String path = "/Users/lirance/Documents/ServiceRecommendationSystem/Performance of service.txt";

        try {
            File file = new File(path);
            FileReader fr;
            fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);
            String line = "";
            int serId = 1;
            while (br.ready()) {
                line = br.readLine();
                String[] data = line.split("\t");
                serValue[serId] = Double.parseDouble(data[1]);
                serId++;
            }
            br.close();
            fr.close();
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        for (int j = 1; j < serValue.length; j++) {
            DataPoint temppoint = new DataPoint();
            temppoint.setDataPointName("" + String.valueOf(j));
            double[] value = {serValue[j]};
            temppoint.setDimensioin(value);
            dpoints.add(temppoint);
        }

        return dpoints;

    }

    public List<Cluster> getClusterLists(int clusterNum) throws Exception {
        ArrayList<DataPoint> dpoints;
        dpoints = (ArrayList<DataPoint>) this.getdataPoints();

        //int clusterNum = 50; //类簇数
//
        ClusterAnalysis ca = new ClusterAnalysis();
        List<String> list = new ArrayList<String>();
        List<Cluster> clu = new ArrayList<Cluster>();
        List<Cluster> clusters = ca.startAnalysis(dpoints, clusterNum);
        for (Cluster cl : clusters) {
            list.add("---" + cl.getClusterName() + "---");
            System.out.println("---" + cl.getClusterName() + "---");
            List<DataPoint> points = cl.getDataPoints();
            for (DataPoint dp : points) {
                list.add(dp.getDataPointName() + ":" + dp.getDimensioin()[0] + " ");
                System.out.print(dp.getDataPointName() + ":" + dp.getDimensioin()[0] + " ");
            }

            System.out.println("");
            clu.add(cl);
        }
        return clu;
    }

    public void insert(int clusterNum) throws Exception {   //插入数据库。
        List<Cluster> clu = getClusterLists(clusterNum);
        for (int i = 0; i < clu.size(); i++) {   //数据库插入操作
            String cluNam = clu.get(i).getClusterName();
            List<DataPoint> dpLists = clu.get(i).getDataPoints();
            for (int j = 0; j < dpLists.size(); j++) {
                int wsid = Integer.parseInt(dpLists.get(j).getDataPointName());
                new GetServiceCallList().updateClustNam(cluNam, wsid);
            }
        }

    }

}
